package com.codeoss.framework.view.pagebean;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.codeoss.framework.context.YunContext;
import com.codeoss.framework.data.metadata.Order;
import com.codeoss.framework.data.metadata.Query;
import com.codeoss.framework.data.metadata.Restrictions;
import com.codeoss.framework.data.metadata.Table;
import com.codeoss.framework.data.metadata.TableData;
import com.codeoss.framework.data.store.ITableStore;
import com.codeoss.framework.expression.Expression;
import com.codeoss.framework.expression.IScriptServiceStore;
import com.codeoss.framework.util.DBUtil;
import com.codeoss.framework.util.StringUtils;
import com.codeoss.framework.view.clientscript.TreeAddNodeClientScript;
import com.codeoss.framework.view.clientscript.TreeRemoveNodeClientScript;
import com.codeoss.framework.view.clientscript.TreeUpdateNodeClientScript;
import com.codeoss.framework.view.component.Component;
import com.codeoss.framework.view.component.IDataBindSource;
import com.codeoss.framework.view.component.IDataBinding;
import com.codeoss.framework.view.component.Message;
import com.codeoss.framework.view.component.Page;
import com.codeoss.framework.view.component.Tree;
import com.codeoss.framework.view.datasource.DataSourceConfig;
import com.codeoss.framework.view.model.HierarchyData;
import com.codeoss.framework.view.pagebean.crud.DeleteRequest;
import com.codeoss.framework.view.pagebean.crud.PageBeanCRUDUtil;
import com.codeoss.framework.view.pagebean.crud.SelectRequest;
import com.codeoss.framework.view.pagebean.crud.SelectResponse;
import com.codeoss.framework.view.pagebean.crud.UpdateRequest;
import com.codeoss.framework.view.service.IVariableService;
import com.codeoss.framework.view.util.DataSourceUtil;
import com.codeoss.framework.view.util.PageBeanUtil;

@Service
public class TreeViewPageBean extends FormViewPageBean {
	@Autowired
	private IVariableService variableService;
	@Autowired
	private DataSource dbDataSource;
	@Autowired
	private ITableStore tableStore;

	public static final String KEY_TREE = "__tree__";
	@Autowired
	private PageBeanUtil pageBeanUtil;
	@Autowired
	private DataSourceUtil dataSourceUtil;
	@Autowired
	private PageBeanCRUDUtil pageBeanCRUDUtil;
	@Autowired
	private IScriptServiceStore scriptServiceStore;
	@Autowired
	private DBUtil dbUtil;
	private static final String TREE_VARNAME="_tree_id_";
	public void beforeInit() {
		YunContext yunContext = YunContext.getCurrentContext();
		Page page = yunContext.getPage();
		if (page.isInit()) {
			return;
		}
		
		pageBeanUtil.getComponent(yunContext, page, "tree");
		Tree tree = (Tree) yunContext.getAttribute("__component__");
		tree.setVarName(TREE_VARNAME);
		page.setAttribute(KEY_TREE, tree);
		
		List<IDataBinding> formDataBindingList = new ArrayList<IDataBinding>();
		pageBeanUtil.getFormFieldList(page, formDataBindingList);
		page.setAttribute(KEY_FORM_FIELD_LIST, formDataBindingList);

		pageBeanUtil.getComponentList(yunContext, page, "table");
		List<com.codeoss.framework.view.component.Table> tableList =yunContext.getAttribute("__componentList__");
		if(tableList==null) {
			tableList=new ArrayList<com.codeoss.framework.view.component.Table>();
		}
		page.setAttribute(KEY_TABLE_LIST, tableList);

		if (tableList != null) {
			for (int i = 0; i < tableList.size(); i++) {
				com.codeoss.framework.view.component.Table table = tableList.get(i);
				List<IDataBinding> dataBindingList = new ArrayList<IDataBinding>();
				pageBeanUtil.getDataBindingList(table, dataBindingList);
				page.setAttribute(KEY_TABLE_FIELD_LIST + table.getId(), dataBindingList);
			}
		}
		
		page.setInit(true);
	}

	public void init() {
		YunContext yunContext = YunContext.getCurrentContext();
		Page page = yunContext.getPage();
		Tree tree = (Tree) page.getAttribute(KEY_TREE);

		DataSourceConfig dataSourceConfig = dataSourceUtil.getDataSourceConfigById(page, tree.getDataSource());
		Table table=tableStore.get(dataSourceConfig.getTableName());

        SelectRequest selectRequest=new SelectRequest();
        selectRequest.setMainTable(table);
        
        Query query=new Query();
        Expression whereExpression=dataSourceConfig.getWhereClause();
        if(whereExpression!=null) {
        	String where=(String)scriptServiceStore.getScriptService(whereExpression).eval(whereExpression.getScript(),null);
        	query.add(Restrictions.sql(where));
        }
        String orderBy=dataSourceConfig.getOrderBy();
        if(!StringUtils.isEmpty(orderBy)) {
        	query.addOrder(Order.sql(orderBy));
        }
        selectRequest.setMainQuery(query);
        SelectResponse selectResponse=pageBeanCRUDUtil.select(yunContext, selectRequest);
		HierarchyData root = dataSourceUtil.convertTableDataToHierarchyData(yunContext, selectResponse.getTableDataMap().get(table.getTableName()).getData());
		yunContext.setAttribute(tree.getId() + "_data", root);

		dataRefresh();
	}

	protected Map<String, Object> getSubmitFormData() {
		YunContext yunContext = YunContext.getCurrentContext();
		Page page = yunContext.getPage();
		Map<String, Object> dataMap = super.getSubmitFormData();
		if (dataMap.get("id") == null) {
			Tree tree = (Tree) page.getAttribute(KEY_TREE);
			Object parentId = variableService.getVariableValue(yunContext, tree.getVarName());
			dataMap.put("parent_id", parentId);
		}
		return dataMap;
	}

	public void onTreeItemClickHandler() {
		YunContext yunContext = YunContext.getCurrentContext();
		Page page = yunContext.getPage();
		Tree tree = (Tree) page.getAttribute(KEY_TREE);
		Object parentId = variableService.getVariableValue(yunContext, tree.getVarName());
		dataRefresh(parentId);
	}

	@Transactional
	public boolean dataSave() {
		boolean isNew = super.dataSave();
		YunContext yunContext = YunContext.getCurrentContext();
		Page page = yunContext.getPage();
		Tree tree = (Tree) page.getAttribute(KEY_TREE);
		Map<String, Object> dataMap = getSubmitFormData();

		if (isNew) {
			Long parentId = (Long) variableService.getVariableValue(yunContext, tree.getVarName());
			DataSourceConfig dataSourceConfig = dataSourceUtil.getDataSourceConfigById(page, tree.getDataSource());
			String newPath = null;
			Table table=tableStore.get(dataSourceConfig.getTableName());
			if (parentId != null) {
				Query query = new Query();
				query.add(Restrictions.eq("id", parentId));
				
				SelectRequest selectRequest=new SelectRequest();
				selectRequest.setMainTable(table);
				selectRequest.setMainQuery(query);
				SelectResponse selectResponse=pageBeanCRUDUtil.select(yunContext, selectRequest);
				TableData tableData = selectResponse.getTableDataMap().get(table.getTableName());
				String path = (String) tableData.getData().get(0).get("path");
				if (path == null) {
					newPath = dataMap.get("id") + ",";
				} else {
					newPath = path + dataMap.get("id") + ",";
				}
				int seqNo = getSeqNo(yunContext, tree, parentId);
				dataMap.put("seq_no", seqNo);
			} else {
				newPath = dataMap.get("id") + ",";
				dataMap.put("seq_no", 10);
			}
			dataMap.put("path", newPath);
			UpdateRequest updateRequest=new UpdateRequest();
			updateRequest.setMainTable(table);
			updateRequest.setMainDataMap(dataMap);
			pageBeanCRUDUtil.update(yunContext, updateRequest);
			variableService.setVariableValue(yunContext, dataSourceConfig.getTableName() + "_path", newPath);
			variableService.setVariableValue(yunContext, dataSourceConfig.getTableName() + "_seq_no",
					dataMap.get("seq_no"));
		}

		if (isNew) {
			TreeAddNodeClientScript treeAddNodeClientScript = new TreeAddNodeClientScript();
			treeAddNodeClientScript.setTreeId(tree.getId());
			treeAddNodeClientScript.setId((Long) dataMap.get("id"));
			treeAddNodeClientScript.setName((String) dataMap.get("name"));
			yunContext.addClientScript(treeAddNodeClientScript);
		} else {
			TreeUpdateNodeClientScript treeUpdateNodeClientScript = new TreeUpdateNodeClientScript();
			treeUpdateNodeClientScript.setTreeId(tree.getId());
			treeUpdateNodeClientScript.setId((Long) dataMap.get("id"));
			treeUpdateNodeClientScript.setName((String) dataMap.get("name"));
			yunContext.addClientScript(treeUpdateNodeClientScript);
		}
		return isNew;
	}

	@Transactional
	public void dataDelete() {
		YunContext yunContext = YunContext.getCurrentContext();
		Page page = yunContext.getPage();
		List<IDataBinding> formDataBindingList = page.getAttribute(KEY_FORM_FIELD_LIST);
		DataSourceConfig mainDataSourceConfig = dataSourceUtil.getDataSourceConfigById(yunContext.getPage(),
				((IDataBindSource) formDataBindingList.get(0)).getDataSource());
		Object idValue = variableService.getVariableValue(yunContext, mainDataSourceConfig.getTableName() + "_id");
		if(idValue!=null) {
			String sql="select count(1) as count from "+mainDataSourceConfig.getTableName()+" where parent_id="+idValue;
			Integer count=dbUtil.getIntegerValue(dbDataSource, sql);
			if(count>0) {
				throw new RuntimeException("存在子节点,不允许删除");
			}
		}
		Map<String, Object> dataMap = new HashMap<String, Object>();
		dataMap.put("id", idValue);
		Table table=tableStore.get(mainDataSourceConfig.getTableName());
		DeleteRequest deleteRequest=new DeleteRequest();
		deleteRequest.setTable(table);
		deleteRequest.setDataMap(dataMap);
		pageBeanCRUDUtil.delete(yunContext, deleteRequest);
		variableService.setVariableValue(yunContext, mainDataSourceConfig.getTableName() + "_id", null);
		dataRefresh();
		yunContext.addMessage(new Message("删除成功"));

		Tree tree = (Tree) page.getAttribute(KEY_TREE);
		TreeRemoveNodeClientScript treeRemoveNodeClientScript = new TreeRemoveNodeClientScript();
		treeRemoveNodeClientScript.setTreeId(tree.getId());
		treeRemoveNodeClientScript.setId((Long) idValue);
		yunContext.addClientScript(treeRemoveNodeClientScript);
	}

	protected Integer getSeqNo(YunContext yunContext, Component component, Long parentId) {
		Page page = yunContext.getPage();
		Tree tree = (Tree) component;
		DataSourceConfig dataSourceConfig = dataSourceUtil.getDataSourceConfigById(page, tree.getDataSource());
		String tableName = dataSourceConfig.getTableName();
		String sql = "select max(seq_no) as seqno from " + tableName + " where parent_id=" + parentId;
		Integer seqNo = dbUtil.getIntegerValue(dbDataSource, sql);
		if (seqNo == null) {
			seqNo = 10;
		} else {
			seqNo = seqNo + 10;
		}
		return seqNo;
	}
}
